package answercard;

import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.Vector;

/**
 * 图片校正
 *
 * @author chenkn
 * 1.图片灰度化
 * 2.阈值二值化
 * 3.检测轮廓
 * 4.寻找轮廓的包围矩阵，并且获取角度
 * 5.根据角度进行旋转矫正
 * 6.对旋转后的图像进行轮廓提取
 * 7.对轮廓内的图像区域抠出来，成为一张独立图像
 * since 2018/12/27
 */
public class RectificationAnswer {

    static {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void main(String[] args) {
        Mat source = Imgcodecs.imread("D:\\eclipse_wk\\opencv-master\\img\\a8.jpg");
        process(source, 0, 1);
    }

    /**
     * 轮廓查找
     *
     * @param source 源文件
     * @param mode   轮廓获取模式，有
     *               <br>RETR_EXTERNAL=0:只检索最外面的轮廓;
     *               <br>RETR_LIST=1:检索所有的轮廓，并将其放入list中;
     *               <br>RETR_CCOMP=2:检索所有的轮廓，并将他们组织为两层:顶层是各部分的外部边界，第二层是空洞的边界;
     *               <br>RETR_TREE=3:检索所有的轮廓，并重构嵌套轮廓的整个层次。
     * @param method 取得轮廓的方法，边缘近似方法(除了RETR_RUNS使用内置的近似，其他模式均使用此设定的近似算法)。可取值如下:
     *               <br>CV_CHAIN_CODE:以Freeman链码的方式输出轮廓，其他方法输出多边形(顶点的序列)。
     *               <br>CHAIN_APPROX_NONE=1:将所有的连码点，转换成点。
     *               <br>CHAIN_APPROX_SIMPLE=2:压缩水平的、垂直的和斜的部分，也就是，函数只保留他们的终点部分。
     *               <br>CHAIN_APPROX_TC89_L1=3，CV_CHAIN_APPROX_TC89_KCOS=4:使用the flavors of Teh-Chin chain近似算法的一种。
     *               <br>CV_LINK_RUNS=5:通过连接水平段的1，使用完全不同的边缘提取算法。使用RETR_LIST检索模式能使用此方法。
     */
    static void process(Mat source, int mode, int method) {
        Mat srcImage2 = new Mat();
        Mat srcImage3 = new Mat();
        Mat srcImage4 = new Mat();
        Mat srcImage5 = new Mat();
        Imgproc.cvtColor(source, srcImage2, Imgproc.COLOR_RGB2GRAY);
        Imgproc.adaptiveThreshold(srcImage2, srcImage3, 255, Imgproc.ADAPTIVE_THRESH_MEAN_C, Imgproc.THRESH_BINARY_INV, 51, 10);
        Vector<MatOfPoint> contours = new Vector<>();
        //Imgproc.findContours(srcImage3, contours, new Mat(), mode, method,new Point());//查找轮廓

        Mat destination = Mat.zeros(source.size(), CvType.CV_8UC3);
        Mat element = Imgproc.getStructuringElement(0, new Size(2 * 1 + 1, 2 * 1 + 1));
        Imgproc.morphologyEx(source, destination, 2, element);//开运算
        Imgproc.erode(srcImage3, srcImage4, element);
        Imgproc.dilate(srcImage4, srcImage5, element);
//        Imgcodecs.imwrite("D://ask//srcImage5.jpg", srcImage5);
        Imgproc.findContours(srcImage5, contours, new Mat(), mode, method, new Point());
        System.out.println("chapter1.size() = " + contours.size());
        //查找最大轮廓
        MatOfPoint matOfPoint = null;
        for (int i = 0; i < contours.size(); i++) {
            matOfPoint = contours.get(i);
            Rect rm = Imgproc.boundingRect(matOfPoint);
            if (rm.area() > 50000) {
                break;
            }
        }
        Rect rm = Imgproc.boundingRect(matOfPoint);
        Mat maxMat = source.submat(new Rect(rm.x, rm.y, rm.width, rm.height));
        Imgcodecs.imwrite("D://ask//maxMat.jpg", maxMat);
        MatOfPoint2f matOfPoint2f = new MatOfPoint2f();
        matOfPoint.convertTo(matOfPoint2f, CvType.CV_32FC1);

        Mat mat = new Mat();
        RotatedRect rotatedRect = Imgproc.minAreaRect(matOfPoint2f);
        Imgproc.boxPoints(rotatedRect, mat);
        System.out.println("rotatedRect.angle = " + rotatedRect.angle);
//        Imgcodecs.imwrite("D://ask//lk3.jpg", mat);
        Mat roiImage = new Mat(maxMat.rows(), maxMat.cols(), CvType.CV_8UC3, new Scalar(0));
//        Imgproc.drawContours(srcImage2, contours, -1, new Scalar(255), 20);
        source.copyTo(roiImage, srcImage2);
        Imgcodecs.imwrite("D://ask//lk2.jpg", roiImage);//获取选择题轮廓
        Mat ratationedImg = new Mat(roiImage.rows(), roiImage.cols(), CvType.CV_8UC1, new Scalar(0));
        //对RoiSrcImg进行旋转
        Point center = rotatedRect.center;//中心点
        Mat mat1 = Imgproc.getRotationMatrix2D(center, rotatedRect.angle, 1);
        Imgproc.warpAffine(roiImage, ratationedImg, mat1, roiImage.size(), 1, 0, new Scalar(0));
        Imgcodecs.imwrite("D://ask//RatationedImg.jpg", ratationedImg);//旋转后的图片
       /* Mat template = Imgcodecs.imread("D:\\eclipse_wk\\opencv-master\\img\\template.jpg");
        DynAnswerCard.process(ratationedImg,template,4);*/
//        AnswerCard.process(ratationedImg);
    }
}
